# coding=utf-8
import time
from utils.redis import Redis
from utils.redis import Redis


# redis互斥锁
class ExcludeLock(object):
    @staticmethod
    def tryLock(key):  # 尝试获取互斥锁，实现解决缓存击穿
        flag = Redis.setnx(key, 1)
        # print(flag)
        if flag:
            Redis.expire(key, 10)
            return True
        return False

    @staticmethod
    def unLock(key):  # 释放互斥锁
        return Redis.delete(key)


# 定义分布式锁
class DistLock(object):
    unLock_script = ""
    with open('lua_script/unLock.lua', 'r', encoding='utf-8') as file:
        unLock_script = file.read()
        # print(unLock_script)
    delay_lua_script = ""
    with open('lua_script/delayLock.lua', 'r', encoding='utf-8') as file:
        delay_lua_script = file.read()
        # print(delay_lua_script)

    def __init__(self, key, only_id):
        self.key = key
        self.only_id = only_id

    def tryLock(self, expire=10):
        flag = Redis.set_with_expire(key=self.key, value=self.only_id, expire=expire)
        return flag

    def unLock(self):  # 释放锁
        # 为保证原子性，调用lua脚本
        return Redis.register_script(DistLock.unLock_script, keys=[self.key], args=[self.only_id])

    def delay_lock(self, expires=10):
        """需要开启一个子线程来对锁进行延期"""
        while True:
            time.sleep(expires // 3)
            # 延时失败就代表业务代码执行完毕
            flag = Redis.register_script(DistLock.delay_lua_script, keys=[self.key], args=[self.only_id, expires])
            if not flag:
                break


################################## 封装一个ReentrantRedLock ###########################
import redis
from setting import REDIS_HOST as host, REDIS_PORT as port, REDIS_DB as db
from utils import rebuild_redlock

# 使用连接池
pool = redis.ConnectionPool(host=host, port=port, max_connections=100)  # 最多可以有100个线程连接
r = redis.StrictRedis(host=host, port=port, db=db, password="", socket_timeout=1, connection_pool=pool)
# 如果是多个redis服务器，直接添加就好
connection_details = [r, ]
retry_times = 5  # 加锁失败重试次数


class ReentrantRedLock(object):

    def __init__(self, key, ttl=3000):
        self.Lock = rebuild_redlock.ReentrantRedLock(key, connection_details, retry_times, ttl=ttl)

    def tryLock(self):
        return self.Lock.acquire()

    def unLock(self):
        self.Lock.release()
